package utils

import (
	"blog/app/models"
	RateModel "blog/app/models/rate_model"
	"context"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	redis "github.com/go-redis/redis/v8"
	"github.com/spf13/viper"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

// InitConfig 初始化项目配置信息
func InitConfig() {
	viper.SetConfigName("app")    // 读取的配置文件名
	viper.AddConfigPath("config") // 读取的配置目录
	err := viper.ReadInConfig()
	if err != nil {
		fmt.Println("读取viper错误", err)
	}
}

var MySqlDB *gorm.DB
var MysqlErr error

// InitMysql 初始化连接MySQL
func InitMysql() {
	dns := viper.GetString("mysql.dns")
	MySqlDB, MysqlErr = gorm.Open(mysql.Open(dns), &gorm.Config{
		// gorm日志模式：silent
		//Logger: logger.Default.LogMode(logger.Silent), 不显示SQL
		Logger: logger.Default.LogMode(logger.Info), // 显示所有SQL
		// 外键约束
		DisableForeignKeyConstraintWhenMigrating: true,
		// 禁用默认事务（提高运行速度）
		SkipDefaultTransaction: true,
		NamingStrategy: schema.NamingStrategy{
			// 使用单数表名，启用该选项，此时，`User` 的表名应该是 `user`
			SingularTable: true,
		},
	})
	if MysqlErr != nil {
		fmt.Println("初始化MySQL失败", MysqlErr)
	}
	fmt.Println("初始化MySQL成功")
	MySqlDB.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4") // 设置MySQL数据格式为utf8mb4
	fmt.Println("开始自动化建表")
	//newMysqltables()
	createRateTables()
}

// 汇率系统初始化
func createRateTables() {
	fmt.Println("开始自动化建表modela")
	err := createTableIfExist(
		&RateModel.CurrencyName{},
		&RateModel.RateRecord{},
		&RateModel.User{},
		&RateModel.UsdCny{},
		&RateModel.CnyUsd{},
		&RateModel.LunarCalendar{},
		&models.UserBasic{},
	)
	if err != nil {
		fmt.Println("初始化表失败", err)
	}
}

// CREATE DATABASE demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

func createTableIfExist(models ...interface{}) error {
	for _, model := range models {
		err := MySqlDB.AutoMigrate(model)
		if err != nil {
			fmt.Printf("初始化表%T失败, err: %v\n", model, err)
			return err
		}
	}
	return nil
}

// 初始化数据表 - 本地生活小程序API
func newMysqltables() {
	err := MySqlDB.AutoMigrate(&models.UserBasic{})
	if err != nil {
		fmt.Println("初始化表UserBasic失败", err)
		return
	}
	err = MySqlDB.AutoMigrate(&models.Banner{})
	if err != nil {
		fmt.Println("初始化表Banner失败", err)
		return
	}
	err = MySqlDB.AutoMigrate(&models.Category{})
	if err != nil {
		fmt.Println("初始化表Category失败", err)
		return
	}
}

var RedisDB *redis.Client

// InitRedis 初始化redis
func InitRedis() {
	RedisDB = redis.NewClient(&redis.Options{
		Addr: viper.GetString("redis.addr"),
		DB:   viper.GetInt("redis.DB"),
	})
	fmt.Println(RedisDB)
}

// ---------------------- 初始化 etcd 连接 ------------------------------

var (
	EtcdCli    *clientv3.Client
	EtcdCtx    context.Context
	EtcdCancel context.CancelFunc
)

func InitEtcd() {
	//ipHost := viper.GetString("etcd.host")
	EtcdCli, err := clientv3.New(clientv3.Config{
		//Endpoints:   []string{ipHost}, //如果是集群，就在后面加所有的节点[]string{"localhost:2379", "localhost:22379", "localhost:32379"},
		Endpoints:   []string{"192.168.64.128:2379"}, //如果是集群，就在后面加所有的节点[]string{"localhost:2379", "localhost:22379", "localhost:32379"},
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		// handle error!
		fmt.Printf("connect to etcd failed, err:%v\n", err)
		return
	}
	//EtcdCtx, EtcdCancel := context.WithTimeout(context.Background(), time.Second)
	fmt.Println("启动etcd成功", EtcdCli)
	//defer cli.Close()
	//ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	//resp, err := EtcdCli.Get(ctx, "address")
	//cancel()
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}
	//fmt.Println(resp)
	//for _, ev := range resp.Kvs {
	//	fmt.Println(string(ev.Key), string(ev.Value))
	//}
}

func InitLogPath() {
	// 获取当前日期
	currentDate := time.Now().Format("2006-01-02")
	// 构建日志文件路径和名称
	logFilePath := fmt.Sprintf("runtime/log/log_%s.log", currentDate)

	// 打开或创建日志文件
	f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
	if err != nil {
		log.Fatalf("打开或创建日志文件失败: %v", err)
	}
	// 这里注释掉就不会关闭日志记录,系统退出时会自动关闭
	//defer func() {
	//	err := f.Close()
	//	if err != nil {
	//		log.Println("关闭日志文件失败:", err)
	//	}
	//}()

	// 设置日志输出到文件和控制台
	multiWriter := io.MultiWriter(os.Stdout, f)
	log.SetOutput(multiWriter)

	// 设置日志格式
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

var (
	// MongoClient 外放出去进行使用
	MongoClient *mongo.Client
	MyDataBase  *mongo.Database
)

// InitMongoDB 初始化连接Mongo
func InitMongoDB() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 替换为你的MongoDB连接字符串
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")

	var err error
	MongoClient, err = mongo.Connect(ctx, clientOptions)
	if err != nil {
		log.Fatal(err)
	}

	// 检查连接是否成功
	err = MongoClient.Ping(ctx, nil)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("成功连接到MongoDB！")
	// 设置默认的database
	MyDataBase = MongoClient.Database("blog")
}

func CloseMongoDB() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := MongoClient.Disconnect(ctx); err != nil {
		log.Fatal(err)
	}
	log.Println("已断开与MongoDB的连接")
}
